#include <cv.h>
#include <highgui.h>
#include <iostream>
#include<fstream>
using namespace std;

#define MAX_Hist 1000

IplImage * image;
bool select_object = true;
CvRect selection;
CvPoint origin;
CvHistogram *hists[2];
int h_bins = 256;


CvScalar hsv2rgb( float hue )
{
    int rgb[3], p, sector;
    static const int sector_data[][3]=
        {{0,2,1}, {1,2,0}, {1,0,2}, {2,0,1}, {2,1,0}, {0,1,2}};
    hue *= 0.033333333333333333333333333333333f;
    sector = cvFloor(hue);
    p = cvRound(255*(hue - sector));
    p ^= sector & 1 ? 255 : 0;

    rgb[sector_data[sector][0]] = 255;
    rgb[sector_data[sector][1]] = 0;
    rgb[sector_data[sector][2]] = p;

    return cvScalar(rgb[2], rgb[1], rgb[0],0);
}

CvHistogram * CalHist(IplImage *src, char *name)
{
    IplImage* hsv = cvCreateImage( cvGetSize(src), 8, 3 );
    IplImage* h_plane = cvCreateImage( cvGetSize(src), 8, 1 );
    IplImage* planes[] = { h_plane};

    /** H 分量划分为16个等级，S分量划分为8个等级 */
    
    int hist_size[] = {h_bins};

    /** H 分量的变化范围 */
    float h_ranges[] = { 0, 180 };

    /** S 分量的变化范围*/
    float* ranges[] = { h_ranges };

    /** 输入图像转换到HSV颜色空间 */
    cvCvtColor( src, hsv, CV_BGR2HSV );
    cvCvtPixToPlane( hsv, h_plane,0, 0, 0 );

    /** 创建直方图，二维, 每个维度上均分 */
    CvHistogram * hist = cvCreateHist( 1, hist_size, CV_HIST_ARRAY, ranges, 1 );
    /** 根据H,S两个平面数据统计直方图 */
    cvCalcHist( planes, hist, 0, 0 );

    /** 获取直方图统计的最大值，用于动态显示直方图 */
    float max_value;
    cvGetMinMaxHistValue( hist, 0, &max_value, 0, 0 );
    cout<<max_value<<endl;

    /** 设置直方图显示图像 */
    int height = 180;
    int width = (h_bins*3);
    IplImage* hist_img = cvCreateImage( cvSize(width,height), 8, 3 );
    cvZero( hist_img );

    int bin_w = width / h_bins;
    for(int h = 0; h < h_bins; h++)
    {
        int val = cvRound( cvGetReal1D(hist->bins,h)*hist_img->height/max_value );
                CvScalar color = hsv2rgb(h*180.f/h_bins);
                cvRectangle( hist_img, cvPoint(h*(bin_w),hist_img->height),
                             cvPoint((h+1)*(bin_w),hist_img->height - val),
                             color, -1, 8, 0 );
    }

    cvShowImage( name, hist_img );

    cvReleaseImage(&hsv);
    cvReleaseImage(&h_plane);

    return hist;
}

void CalD()
{
    double maps[2][300], max0 = 0, max1 = 0, mid0 = 0, mid1 = 0;
    int i, j, k;

    for(i = 0; i < h_bins; i++) {
        maps[0][i] = cvGetReal1D(hists[0]->bins,i);
        if(maps[0][i] > max0) max0 = maps[0][i];

        maps[1][i] = cvGetReal1D(hists[1]->bins,i);
        if(maps[1][i] > max1) max1 = maps[0][i];
    }

    //根据最大值统一到0到 MAX_Hist的范围内，如果最大值小于MAX_Hist则不变
    if(max0 > MAX_Hist){
        for(i = 0; i < h_bins; i++) {
            maps[0][i] = maps[0][i]/max0 * MAX_Hist;
            mid0 += maps[0][i];
        }
    }

    if(max1 > MAX_Hist){
        for(i = 0; i < h_bins; i++) {
            maps[1][i] = maps[1][i]/max1 * MAX_Hist;
            mid1 += maps[1][i];
        }
    }

    mid0 /= h_bins;
    mid1 /= h_bins;
    
    double variance[300] = {0}, mid = 0, dis = 0;
    for(i = 0; i < h_bins; i++) {
        variance[i] = maps[0][i] - maps[1][i];
        if(variance[i] < 0) variance[i] = -variance[i];
        mid += variance[i];
    }

    mid /= h_bins;
    for(i = 0; i < h_bins; i++) {
        dis += (mid - variance[i]) * (mid - variance[i]);
    }
    cout<<"方差为:"<<dis<<endl;

}

void on_mouse( int event, int x, int y, int flags, void* param )
{

    if( image->origin )
        y = image->height - y;

    if( select_object )
    {
        selection.x = MIN(x,origin.x);
        selection.y = MIN(y,origin.y);
        selection.width = selection.x + CV_IABS(x - origin.x);
        selection.height = selection.y + CV_IABS(y - origin.y);

        selection.x = MAX( selection.x, 0 );
        selection.y = MAX( selection.y, 0 );
        selection.width = MIN( selection.width, image->width );
        selection.height = MIN( selection.height, image->height );
        selection.width -= selection.x;
        selection.height -= selection.y;
    }

    switch( event )
    {
    case CV_EVENT_LBUTTONDOWN:
        origin = cvPoint(x,y);
        selection = cvRect(x,y,0,0);
        break;
    case CV_EVENT_LBUTTONUP:
        if( selection.width > 0 && selection.height > 0 ){
            //select_object = false;
            IplImage *part = cvCreateImage(cvSize(selection.width, selection.height), 8, 3);
            cvSetImageROI(image, selection);
            cvCopy(image, part);
            cvShowImage("Part", part);
            hists[1] = CalHist(part,"PartHist");
            CalD();
        }
        break;
    }


}


int main( int argc, char** argv )
{


	IplImage * src= cvLoadImage("./pic.jpg");
        image = src;
        

        cvNamedWindow( "Source", 1 );
	cvShowImage( "Source", src ); 
        cvNamedWindow( "Part", 1 );
        cvNamedWindow( "PartHist", 1 );
        cvNamedWindow( "Hist", 1 );


        cvMoveWindow("Source", 0, 0);
        cvMoveWindow("Hist", 700, 0);
        cvMoveWindow("Part", 0, 700);
        cvMoveWindow("PartHist", 700, 700);

        cvSetMouseCallback( "Source", on_mouse, 0 );

        hists[0] = CalHist(src, "Hist");
        
	


	

	cvWaitKey(0);
}